import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Random;


public class QueryFactory {

	private static final int datapacketsize = 1088;

	static String search(String keywords)
	{
		return "SEARCH id" + new Random().nextInt(99999999)+ " " + keywords;
	}
	
	static String found(String searchid, String HashValue, long size, String filename)
	{
		return  "FOUND" + " " + searchid + " " + HashValue + " " +  size + " " + filename;
	}
	
	static String get(String HashValue, String chunks)
	{
		return "GET " + HashValue + " " + chunks;
	}
	
	static byte[] getChunkPacket (String hashvalue, int chunknumber, byte[] reserved,byte[] chunk)
	{
		ByteBuffer result = ByteBuffer.allocate(datapacketsize); 
		result.order(ByteOrder.LITTLE_ENDIAN);
		
		result.put(hexStringToByteArray(hashvalue));
		
		result.putLong(chunknumber);
		
		result.put(reserved);
		
		result.put(chunk);
		
		return result.array();
	}
	
	static boolean verifyChunkIntegrity(byte[] chunk,byte[] chunkChecksum,String algorithm)
	{
		if(chunkChecksum[20]==1 && chunkChecksum[21]==2 && chunkChecksum[22]==3 && chunkChecksum[23]==4)
		{
			byte[] tmp = new byte[20];
			System.arraycopy(chunkChecksum, 0, tmp, 0, 20);
			
			if(Arrays.equals(chunkCheckSum(chunk,algorithm), tmp) )
			{
				return true;
			}
			return false;
		}
		return true;
	}
	
	static byte[] chunkCheckSum(byte[] chunk,String algorithm)
	{
		
		try {
			MessageDigest md;
			md = MessageDigest.getInstance(algorithm);
			md.update(chunk);
			return md.digest();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
		return null;		
	}
	
	static String getHashValue(String algorithm, String filepath) throws Exception
	{
		MessageDigest md = MessageDigest.getInstance(algorithm);
		FileInputStream fis = new FileInputStream(filepath);
 
		byte[] dataBytes = new byte[1024];
 
		int nread = 0;
		while ((nread = fis.read(dataBytes)) != -1) {
			md.update(dataBytes, 0, nread);
		};
		byte[] mdbytes = md.digest();
 
		//convert the byte to hex format
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < mdbytes.length; i++) {
			sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
		}
 
		//System.out.println("Hex format : " + sb.toString());
		//System.out.println("Hex format length : " + sb.toString().length());
		//System.out.println("MD length : " + mdbytes.length);
		
		fis.close();
		return sb.toString();
	}
	
	public static String byteToHexString(byte[] b){
		
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < b.length; i++) {
			sb.append(Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1));
		}
		
		return sb.toString();
	}
	
	// TODO adicionar a bibliografia http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
	public static byte[] hexStringToByteArray(String s) {
	    int len = s.length();
	    byte[] data = new byte[len / 2];
	    for (int i = 0; i < len; i += 2) {
	        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
	                             + Character.digit(s.charAt(i+1), 16));
	    }
	    return data;
	}
	
	// TODO BIBLIOGRAFIA http://snippets.dzone.com/posts/show/93
	public static final byte[] intToByteArray(int value)
	{
        return new byte[] {
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value,
                (byte)0,(byte)0,(byte)0,(byte)0};
	}
	// TODO BIBLIOGRAFIA http://snippets.dzone.com/posts/show/94
	public static int byteArrayToInt(byte[] b) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (b[i + 0] & 0x000000FF) << shift;
        }
        return value;
	}
}
